﻿//
// Created by QU on 24-9-23.
//

#include "Node.h"

Node::Node(const uint16_t payload_len, const uint8_t type_tag, const uint8_t msg_id)
    : BaseNode(payload_len), m_type_tag(type_tag), m_msg_id(msg_id)
{
    if (payload_len > MAX_PAYLOAD_SIZE)
    {
        throw std::invalid_argument("Payload size exceeds maximum allowed size");
    }
}

Node::Node(const std::byte data[], const uint16_t node_len)
    : BaseNode(data + sizeof(uint8_t) * 2, node_len - sizeof(uint8_t) * 2)
{
    if (node_len < MAX_HEADER_SIZE)
    {
        throw std::invalid_argument("Data too short for RecvNode");
    }
    if (node_len > MAX_NODE_SIZE)
    {
        throw std::invalid_argument("RecvNode size exceeds maximum allowed size");
    }
    m_type_tag = static_cast<uint8_t>(data[0]);
    m_msg_id = static_cast<uint8_t>(data[1]);
}

Node::Node(const SerializedData& serialized_data)
    : Node(serialized_data.buffer.get(), serialized_data.length)
{
}

Node::Node(const Node& other)
    : BaseNode(other), m_type_tag(other.m_type_tag), m_msg_id(other.m_msg_id)
{
}

Node& Node::operator=(const Node& other)
{
    if (this != &other)
    {
        BaseNode::operator=(other);
        m_type_tag = other.m_type_tag;
        m_msg_id = other.m_msg_id;
    }
    return *this;
}

Node::Node(Node&& other) noexcept
    : BaseNode(std::move(other)),
      m_type_tag(std::exchange(other.m_type_tag, 0)),
      m_msg_id(std::exchange(other.m_msg_id, 0))
{
}

Node& Node::operator=(Node&& other) noexcept
{
    if (this != &other)
    {
        BaseNode::operator=(std::move(other));
        m_type_tag = std::exchange(other.m_type_tag, 0);
        m_msg_id = std::exchange(other.m_msg_id, 0);
    }
    return *this;
}

Node::SerializedData Node::serialize() const
{
    auto buffer = std::make_unique<std::byte[]>(MAX_HEADER_SIZE + m_payload_len);

    buffer[0] = static_cast<std::byte>(m_type_tag);
    buffer[1] = static_cast<std::byte>(m_msg_id);

    const uint16_t net_payload_len = boost::endian::native_to_big(m_payload_len);
    std::memcpy(buffer.get() + 2, &net_payload_len, sizeof(uint16_t));

    std::memcpy(buffer.get() + MAX_HEADER_SIZE, m_payload.get(), m_payload_len);

    return { std::move(buffer), static_cast<uint16_t>(MAX_HEADER_SIZE + m_payload_len) };
}

Node Node::deserialize(const std::byte* data, const uint16_t size)
{
    if (size < MAX_HEADER_SIZE)
    {
        throw std::invalid_argument("Data too short for RecvNode");
    }
    return Node(data, size);
}

const std::byte* Node::getNodePayloadPointer() const noexcept
{
    return BaseNode::getNodePayloadPointer();
}

uint16_t Node::getNodePayloadSize() const noexcept
{
    return BaseNode::getNodePayloadSize();
}

uint16_t Node::getNodeFullSize() const noexcept
{
    return getNodePayloadSize() + MAX_HEADER_SIZE;
}

uint8_t Node::getTypeTag() const noexcept
{
    return m_type_tag;
}

uint8_t Node::getMsgId() const noexcept
{
    return m_msg_id;
}

std::ostream& operator<<(std::ostream& os, const Node& node)
{
    os << static_cast<const BaseNode&>(node);
    os << "Type Tag: " << static_cast<int>(node.m_type_tag) << "\n";
    os << "Message ID: " << static_cast<int>(node.m_msg_id) << "\n";
    return os;
}
